Type MaxMod_Channel

	Const ClickDelaySize		:Int   	= 128					' number of samples to ramp/interpolate
	Const ClickFrac				:Double = 1!/ClickDelaySize
 
	Const volumestep			:Double = 1!/$40
	Const short2float			:Double = 1!/32767
	Const slidestep				:Double = 12!/255 

	Global SineWave:Double[] =   [ 0.00000000000000000!, 0.09651392091451500!, 0.19212671735370854!, 0.28594567839868923!, 0.37709484168832047!, ..
								   0.46472317204376862!, 0.54801250735466989!, 0.62618519753831370!, 0.69851136524893698!, 0.76431572054584829!, ..
								   0.82298386589365646!, 0.87396803262651790!, 0.91679219531658229!, 0.95105651629515353!, 0.97644107882927200!, ..
								   0.99270887409805397!, 0.99970801408019294!, 0.99737314969149116!, 0.98572608093165093!, 0.96487555334355146!, ..
								   0.93501624268541483!, 0.89642693729570377!, 0.84946793512152108!, 0.79457767971375426!, 0.73226866659777379!, ..
								   0.66312265824079530!, 0.58778525229247314!, 0.50695985381359021!, 0.42140110777252926!, 0.33190785312852855!, ..
								   0.23931566428755763!, 0.14448904956922157!, 0.04831337952550726!,-0.04831337952550714!,-0.14448904956922098!, ..
								  -0.23931566428755771!,-0.33190785312852844!,-0.42140110777252893!,-0.50695985381359010!,-0.58778525229247303!, ..
								  -0.66312265824079530!,-0.73226866659777323!,-0.79457767971375415!,-0.84946793512152108!,-0.89642693729570377!, ..
								  -0.93501624268541472!,-0.96487555334355146!,-0.98572608093165093!,-0.99737314969149105!,-0.99970801408019294!, ..
								  -0.99270887409805397!,-0.97644107882927211!,-0.95105651629515364!,-0.91679219531658229!,-0.87396803262651779!, ..
								  -0.82298386589365680!,-0.76431572054584851!,-0.69851136524893709!,-0.62618519753831392!,-0.54801250735467000!, ..
								  -0.46472317204376834!,-0.37709484168832080!,-0.28594567839868934!,-0.19212671735370909!,-0.09651392091451556!  ]
	Global RampWave:Double[] =	[  0.00000000000000000!,-0.03125000000000000!,-0.06250000000000000!,-0.09375000000000000!,-0.12500000000000000!, ..
								  -0.15625000000000000!,-0.18750000000000000!,-0.21875000000000000!,-0.25000000000000000!,-0.28125000000000000!, ..
								  -0.31250000000000000!,-0.34375000000000000!,-0.37500000000000000!,-0.40625000000000000!,-0.43750000000000000!, ..
								  -0.46875000000000000!,-0.50000000000000000!,-0.53125000000000000!,-0.56250000000000000!,-0.59375000000000000!, ..
								  -0.62500000000000000!,-0.65625000000000000!,-0.68750000000000000!,-0.71875000000000000!,-0.75000000000000000!, ..
								  -0.78125000000000000!,-0.81250000000000000!,-0.84375000000000000!,-0.87500000000000000!,-0.90625000000000000!, ..
								  -0.93750000000000000!,-0.96875000000000000!,-1.00000000000000000!, 0.96875000000000000!, 0.93750000000000000!, ..
								   0.90625000000000000!, 0.87500000000000000!, 0.84375000000000000!, 0.81250000000000000!, 0.78125000000000000!, ..
								   0.75000000000000000!, 0.71875000000000000!, 0.68750000000000000!, 0.65625000000000000!, 0.62500000000000000!, ..
								   0.59375000000000000!, 0.56250000000000000!, 0.53125000000000000!, 0.50000000000000000!, 0.46875000000000000!, ..
								   0.43750000000000000!, 0.40625000000000000!, 0.37500000000000000!, 0.34375000000000000!, 0.31250000000000000!, ..
								   0.28125000000000000!, 0.25000000000000000!, 0.21875000000000000!, 0.18750000000000000!, 0.15625000000000000!, ..
								   0.12500000000000000!, 0.09375000000000000!, 0.06250000000000000!, 0.03125000000000000!, 0.00000000000000000!  ]
	Global SquareWave:Double[] = [-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!, ..
								  -1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!, ..
								  -1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!, ..
								  -1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!, ..
								  -1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!, ..
								  -1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!,-1.00000000000000000!, ..
								  -1.00000000000000000!,-1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, ..
								   1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, ..
								   1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, ..
								   1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, ..
								   1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, ..
								   1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, ..
								   1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!, 1.00000000000000000!  ]

	Field Instrument	:MaxMod_Instrument	' current instrument for each channel
	Field Sample		:MaxMod_Sample		' current sample for each channel
	Field Pos					:Double		' position in audio sample
	Field Note 					:Double		' channels current note
	Field FineTune				:Double		' channels current finetune value
	Field Add					:Double		' fractional amount to move sample position to achieve required frequency
	Field Volume				:Double		' current volume of channel stored as 0 to 1
	Field MixerVolume			:Double		' current volume of channel stored as 0 to 1 used in mixer (ramps to Volume)
	Field Mute					:Int		' true if channel is muted
	Field Tick					:Int		' tick count used for envelopes

	Field KeyOff				:Int		' true if note off (fadeout)
	Field KeyOffValue			:Double		' 
	Field KeyOffStep			:Double		' 

	Field Arped					:Int		' true if arppegiation is applied
	Field PortamentoUp			:Int		' current slide up value
	Field PortamentoDown		:Int		' current slide down value
	Field VolumeSlide			:Double		' current volume slide value
	Field TonePortamentoNote	:Double		' portamento destination note
	Field TonePortamentoValue	:Double		' amount to adjust portamento each tick

	Field VibratoValue			:Double		' current vibrato value		
	Field VibratoWaveForm		:Int		' the wave form to use for vibrato
	Field VibratoSpeed			:Int		' amount to adjust vibrato each tick
	Field VibratoDepth			:Int		' depth of vibrato
	Field VibratoCount			:Int		' current position in vibrato

	Field TremoloWaveForm		:Int		' the wave form to use for tremolo
	Field TremoloSpeed			:Int		' amount to adjust tremolo each tick
	Field TremoloDepth			:Int		' depth of tremolo
	Field TremoloCount			:Int		' current position in tremolo
	Field TremoloValue			:Int		' current tremolo output

	Field LastAV				:Int		' used in anticlick routine
	Field ClickDelay			:Int		' used in anticlick routine
	Field Env					:Double		' precalculated volume value
	Field VolumeEnvelopeIndex	:Int		' channels current volume envelope position
	Field EnvelopePan			:Int = 32	' not implemented yet, 32 is center
	Field Pan					:Double		' current pan of channel       (-1 = left, 0 = center, +1 = right)
	Field FinalPan				:Double		' precalculated pan value
	Field LPanCalc 				:Double		' 
	Field RPanCalc   			:Double		'

	Field LevelL   				:Double
	Field LevelR   				:Double
	Field Scope   				:TBank
	Field ScopePtr				:Float Ptr
	Field ScopeFillPos			:Int
	Field SetFrequency			:Int
	Field SetPan				:Int

	' ------------------------------------------------------------------------------------------------
	' based on mixing routine by Chris C

	Method Mix(LAV:Int Ptr,RAV:Int Ptr,writelength:Int)

		MixerVolume = (Volume+TremoloValue)*Env*KeyOffValue
		LevelL=0 ; LevelR=0
		Local i:Int
		If Not sample Or Add=0 Or Mute
			If LastAV<>0
				For i=0 Until writelength
					LastAV:*0.8
					If Abs(LASTAV)<1 Then Add = 0 ; LASTAV = 0 ; Exit
					If LPanCalc LAV[i]:+(LastAV*LPanCalc) ; LevelL:+Abs(LastAV*LPanCalc)
					If RPanCalc RAV[i]:+(LastAV*RPanCalc) ; LevelR:+Abs(LastAV*RPanCalc)
				Next
				LevelL:/i ; LevelL:/32767
				LevelR:/i ; LevelR:/32767
			EndIf
			Return
		EndIf

		Local av:Double, fp:Int Ptr = Sample.fp
		For i=0 Until writelength
		
			Pos = Sample.FixPos(Pos,Add,True)

			If Pos=>0 And Add<>0
			
				av = Sample.GetAV(Pos,Add)*MixerVolume
				'av = (fp[Pos]+((Sample.FixPos(Pos+Sgn(add),Add)-fp[Pos])*(pos-Int(pos))))*MixerVolume
				'av = Interpolate_Cosine(fp[Pos], Sample.FixPos(Pos+1,Add), Pos)*MixerVolume
				'av	= fp[Pos]*MixerVolume

				Pos:+Add
								
				If ClickDelay>0
					av = av+((lastav-av)*(clickfrac*clickdelay))
					ClickDelay:-1
				EndIf
				LastAV = av

			Else
				LastAV:*0.8
				If Abs(LASTAV)<1 Then Add = 0 ; LASTAV = 0 ; Exit 
				AV = LastAV
			EndIf

			If av<>0
				If Scope
					If ScopeFillPos<(Scope.Capacity()/4)
						ScopePtr[ScopeFillPos] = short2float*av
						ScopeFillPos:+1
					EndIf
				EndIf
				If LPanCalc LAV[i]:+(av*LPanCalc) ; LevelL:+Abs(av*LPanCalc)
				If RPanCalc RAV[i]:+(av*RPanCalc) ; LevelR:+Abs(av*RPanCalc)
			EndIf

		Next 'i
		LevelL:/i ; LevelL:/32767
		LevelR:/i ; LevelR:/32767

	EndMethod

	' ------------------------------------------------------------------------------------------------

	Method PreCalc()
		ENV = Instrument.GetEnvelopeVolume(Tick,VolumeEnvelopeIndex)
	EndMethod

	' ------------------------------------------------------------------------------------------------

	Method CalcKeyOff()
		If Not Instrument Return
		If Instrument.VolFadeout >0
			KeyOffStep=(Instrument.VolFadeout*32)/65536.0
		Else
			KeyOffStep=1.0
		EndIf
	EndMethod

	' ------------------------------------------------------------------------------------------------

	Method ApplyKeyOff()
		If KeyOff
			KeyOffValue:-KeyOffStep
			If KeyOffValue<0 Then Add=0 ; KeyOffValue=0
			MixerVolume:*KeyOffValue
		EndIf
	EndMethod

	' ------------------------------------------------------------------------------------------------

	Method SetFreq()
		If Not Sample Return
		If Add=>0 
			Add = 2^((Note+Finetune+VibratoValue+Sample.RelativeNote-77)/12)
		Else
			Add = -(2^((Note+Finetune+VibratoValue+Sample.RelativeNote-77)/12))
		EndIf		
	EndMethod

	' ------------------------------------------------------------------------------------------------

	Method ApplyVolume(MMTick:Int,SEQNOTE:Int,Value:Int)
		Select True
			Case Value=<$50										'	$10-$50   Set volume Value-$10
				If MMTICK = 0 Then Volume = VolumeStep*(Value-$10)
			Case Value=<$6f										'	Volume slide down
				Volume:-(VolumeStep*(Value-$60))
				If Volume<0 Then Volume=0
			Case Value=<$7f										'	Volume slide up
				Volume:+(VolumeStep*(Value-$70))
				If Volume>1 Then Volume=1
			Case Value=<$8f										'	Fine volume slide down
				If MMTICK = 0 
					Volume:-(VolumeStep*(Value-$80))
					If Volume<0 Then Volume=0
				EndIf
			Case Value=<$9f										'	Fine volume slide up
				If MMTICK = 0 
					Volume:+(VolumeStep*(Value-$90))
					If Volume>1 Then Volume=1
				EndIf
			Case Value=>$a0 And Value=<$af						'	Set vibrato speed
				If MMTICK = 0 Then VibratoSpeed = Value-$a0
			Case Value=>$b0 And Value=<$bf						'	Vibrato
			Case Value=>$c0 And Value=<$cf						'	Set panning
				If MMTICK = 0 
					Pan = ((Value-$c0)-8)*16
					If Pan<-128 Then Pan=-128
					If Pan>128 Then Pan=128
					Pan=(1.0/128)*Pan
					SetPan = True
				EndIf
			Case Value=>$d0 And Value=<$df						'	Panning slide Left
				If MMTICK = 0 
					Pan=128*Pan
					Pan:-(Value-$d0)
					If Pan<-128 Then Pan=-128
					Pan=(1.0/128)*Pan
					SetPan = True
				EndIf
			Case Value=>$e0 And Value=<$ef						'	Panning slide Right
				If MMTICK = 0
					Pan=128*Pan
					Pan:+(Value-$e0)
					If Pan>128 Then Pan=128
					Pan=(1.0/128)*Pan
					SetPan = True
				EndIf
			Case Value=<$ff										'	Tone porta
				If MMTick=0
	                If SEQNOTE > 0 Then TonePortamentoNote = SEQNOTE
					If Value-$f0>0 Then TonePortamentoValue = slidestep*(Value-$f0) ; SetFrequency = True
				EndIf
				DoNotePortamento
		EndSelect

	EndMethod

	' ------------------------------------------------------------------------------------------------

	Field line:Int 
	Field linenote:Int 
	Field inst:Int 
	Field vol:Int 
	Field fx:Int 
	Field fxv:Int 
	Field fxvl:Int 
	Field fxvr:Int 

	Method ApplyCommand(track:MaxMod_Track, parent:MaxMod_Mixer)

		Tick:+1
		Local mmtick:Int = parent.mmtick
		If MMTick=0
			line 		= parent.currentline
			linenote 	= Track.Note[line]
			inst 		= Track.Inst[line]
			vol 		= Track.Vol[line]
			fx 			= Track.FX[line]	
			fxv 		= Track.FXV[line]
			fxvl 		= (fxv & %11110000) Shr 4
			fxvr 		= (fxv & %00001111)
		EndIf

		If (MMTick=0 And Not (FX=CMD_EXTENDED And FXVL=CMD_EX_DELAYNOTE)) Or (FX=CMD_EXTENDED And FXVL=CMD_EX_DELAYNOTE And MMTick=FXVR)

			' apply note
			If linenote
				If linenote=96
					KeyOff = True
					CalcKeyOff()
					linenote=0
					ClickDelay = ClickDelaySize-1
				ElseIf FX<>CMD_PORTAMENTONOTE And FX<>CMD_PORTAMENTONOTE_AND_VOLUMESLIDE
					Tick				= 0
	       			Note 				= linenote
					VolumeEnvelopeIndex = 0
					VibratoCount		= 0
					VibratoValue		= 0
					Pos					= 0
					KeyOff 				= False
					KeyOffStep			= 0
					KeyOffValue			= 1
					ClickDelay 			= ClickDelaySize-1
					ARPED				= False
					SetFrequency		= True
					SetPan				= True
				EndIf
			EndIf
	
			' apply instrument
			If Inst
				If Inst<Parent.Instrument.length
					Instrument = Parent.Instrument[Inst]
				Else
					Instrument = Null
				EndIf
				If Instrument
					Sample = Instrument.GetSample(Note)
					If Sample
						Volume 		= Sample.Volume
						MixerVolume	= Sample.Volume
						FineTune	= Sample.FineTune
						Pan			= Sample.Pan
						ClickDelay 	= ClickDelaySize-1
						SetPan		= True
					Else
						Add 		= 0
						ClickDelay 	= ClickDelaySize-1
					EndIf
				Else
					Sample		= Null
					Add			= 0
					ClickDelay 	= ClickDelaySize-1
				EndIf
			EndIf
			
		EndIf

		If Sample And Note

			If Vol=>$10 Then ApplyVolume(MMTick,linenote,vol)
		
			If FX<>CMD_ARPPEGIATION And ARPED Then SetFrequency=True ; ARPED=False
		
			Select FX
				
  	        	Case CMD_ARPPEGIATION ' --------------------------------------------------
					If FXV
						Select (Tick Mod 3)
							Case 0 ; SetFrequency = True ; ARPED=False 
							Case 1 ; Note:+FXVL ; SetFreq ; Note:-FXVL ; ARPED=True
							Case 2 ; Note:+FXVR ; SetFreq ; Note:-FXVR ; ARPED=True
						EndSelect
					ElseIf ARPED=True
						SetFrequency=True ; ARPED=False
					EndIf
	
	            Case CMD_PORTAMENTOUP ' --------------------------------------------------
					If MMTick=0 And FXV Then PortamentoUp = FXV
					Note:+(slidestep*PortamentoUp)
					SetFrequency = True

    	       	Case CMD_PORTAMENTODOWN ' ------------------------------------------------
					If MMTick=0 And FXV Then PortamentoDown = FXV
					Note:-(slidestep*PortamentoDown)
					SetFrequency = True
		
        	    Case CMD_PORTAMENTONOTE ' ------------------------------------------------
					If MMTick=0
						If linenote>0 Then TonePortamentoNote = linenote
						If FXV>0 Then TonePortamentoValue = slidestep*FXV
						KeyOff 				= False
						KeyOffStep			= 0
						KeyOffValue			= 1
					EndIf
					DoNotePortamento()

           		Case CMD_VIBRATO ' -------------------------------------------------------
					If MMTick=0 And FXV
   						If FXVL Then VibratoSpeed = FXVL
           				If FXVR Then VibratoDepth = FXVR
					EndIf
					DoVibrato()
	
            	Case CMD_PORTAMENTONOTE_AND_VOLUMESLIDE ' --------------------------------
					If MMTick=0
						If linenote Then TonePortamentoNote = linenote
						KeyOff 				= False
						KeyOffStep			= 0
						KeyOffValue			= 1
					EndIf
					DoNotePortamento()
					EFFECT_VolumeSlide(MMTick,FXVL,FXVR)

            	Case CMD_VIBRATO_AND_VOLUMESLIDE ' ---------------------------------------
					DoVibrato()
					EFFECT_VolumeSlide(MMTick,FXVL,FXVR)

            	Case CMD_TREMOLO ' -------------------------------------------------------
					If MMTick=0
			        	If FXVL Then TremoloSpeed = FXVL 
				        If FXVR Then TremoloDepth = FXVR
					EndIf
			       	DoTremolo()

            	Case CMD_SETPAN ' --------------------------------------------------------
					If MMTick=0
						Pan = (1.0/128)*(FXV-128)
						SetPan = True
					EndIf

            	Case CMD_SETSAMPLEOFFSET ' -----------------------------------------------
					If MMTick=0
						Local offset:Int = FXV*256
						If offset < Sample.Length
							Pos 		= offset
							ClickDelay 	= ClickDelaySize-1
						EndIf
					EndIf

            	Case CMD_VOLUMESLIDE ' ---------------------------------------------------
					EFFECT_VolumeSlide(Parent.MMTick, FXVL, FXVR)

            	Case CMD_SETVOLUME ' -----------------------------------------------------
					If MMTick=0
						ClickDelay 	= ClickDelaySize-1
						Volume		= Min(Max(VolumeStep*FXV,0),1)
					EndIf

   	        	Case CMD_EXTENDED ' ------------------------------------------------------
   	            	Select FXVL

   	                	Case CMD_EX_FINEPORTAMENTOUP ' -----------------------------------
							If MMTick=0 And FXVR
								PortamentoUp = FXVR
								VibratoCount = 0
								VibratoValue = 0
								Note:+(slidestep*PortamentoUp)
								SetFrequency = True
							EndIf

    	                Case CMD_EX_FINEPORTAMENTODOWN ' ---------------------------------
							If MMTick=0 And FXVR
								PortamentoDown	= FXVR
								VibratoCount 	= 0
								VibratoValue	= 0
								Note:-(slidestep*PortamentoDown)
								SetFrequency 	= True
							EndIf

   		               	'Case CMD_EX_GLISSANDOCONTROL ' ----------------------------------

                    	Case CMD_EX_VIBRATOCONTROL ' -------------------------------------
							If MMTick=0 Then VibratoWaveForm = FXVR

                    	Case CMD_EX_SETFINETUNE ' ----------------------------------------
							If MMTick=0 
								If FXVR>7 Then FXVR:-16
								If FXVR<-7 Then FXVR=-7
								FineTune = (1!/8)*FXVR
								SetFrequency = True
							EndIf
								
   	                	Case CMD_EX_TREMOLOCONTROL ' -------------------------------------
							If MMTick=0 Then TremoloWaveForm = FXVR	
								
                    	Case CMD_EX_SETPAN16 ' -------------------------------------------
							If MMTick
								Pan=(1!/8)*(FXVR-8)
								SetPan=True
							EndIf

                    	Case CMD_EX_RETRIGNOTE ' -----------------------------------------
							If FXVR
								If (Tick Mod FXVR)=0 Then TICK=0 ; POS=0 ; SetFrequency=True
							ElseIf MMTick=0
								TICK=0 ; POS=0 ; SetFrequency=True
							EndIf

                    	Case CMD_EX_FINEVOLUMEUP ' ---------------------------------------
							If MMTick=0 Then Volume=Min(Max(Volume+(VolumeStep*FXVR),0),1)
	
                    	Case CMD_EX_FINEVOLUMEDOWN ' -------------------------------------
							If MMTick=0 Then Volume=Min(Max(Volume-(VolumeStep*FXVR),0),1)
								
                    	Case CMD_EX_NOTECUT ' --------------------------------------------
							If MMTick = FXVR 
								Volume=0
								ClickDelay=ClickDelaySize-1
							EndIf
									
               		EndSelect
	
				Case 20	; KeyOff = True
					
				Case CMD_SETENVELOPEPOSITION ' -------------------------------------------
					
				Case CMD_PANNINGSLIDE ' --------------------------------------------------
					
				Case CMD_MULTIRETRIGNOTE ' -----------------------------------------------
					
				Case CMD_EXTRAFINEPORTAMENTO ' -------------------------------------------
					Select FXVL
						Case 1	' EXTRA FINE PORTAMENTO UP
							If MMTick=0 And FXVR
								PortamentoUp = FXVR
								VibratoCount = 0
								VibratoValue = 0
								Note:+(slidestep*PortamentoUp)/4
								SetFrequency = True
							EndIf
						Case 2 ' EXTRA FINE PORTAMENTO DOWN
							If MMTick=0 And FXVR
								PortamentoDown	= FXVR
								VibratoCount 	= 0
								VibratoValue	= 0
								Note:-(slidestep*PortamentoDown)/4
								SetFrequency 	= True
							EndIf
					EndSelect
						
			EndSelect
			
			If SetFrequency Then SetFreq ; SetFrequency = False
			If SetPan Then CalculatePan(Pan,EnvelopePan, LPanCalc, RPanCalc) ; SetPan = False

		EndIf

	EndMethod

	' ------------------------------------------------------------------------------------------------

	Method EFFECT_VolumeSlide(MMTick:Int,LFXV:Int,RFXV:Int)
		If MMTick=0
			If LFXV And RFXV 											' DO NOTHING
		    ElseIf LFXV   												' Slide Volume Up
		    	VolumeSlide=(VolumeStep*LFXV)
		    ElseIf RFXV 												' Slide Volume Down
		    	VolumeSlide=-(VolumeStep*RFXV)
			Else
				VolumeSlide=0
		    EndIf
		EndIf
		If Tick Then Volume=Min(Max(Volume+VolumeSlide,0),1)
	EndMethod

	' ------------------------------------------------------------------------------------------------

	Method DoNotePortamento()
		If Not (Add And Sample) Then Return
		If Note < TonePortamentoNote
			Note:+TonePortamentoValue
			If Note > TonePortamentoNote Then Note = TonePortamentoNote
			SetFrequency = True
		ElseIf Note > TonePortamentoNote
			Note:-TonePortamentoValue
			If Note < TonePortamentoNote Then Note = TonePortamentoNote
			SetFrequency = True
		EndIf
	EndMethod
	
	' ------------------------------------------------------------------------------------------------

	Method DoVibrato()
		If Add=0 Return
	    If VibratoCount>64 Then VibratoCount:Mod 64
		Select VibratoWaveForm
			Case 0,4 ; VibratoValue = (SlideStep*SineWave[VibratoCount])*VibratoDepth
			Case 1,5 ; VibratoValue = (SlideStep*RampWave[VibratoCount])*VibratoDepth
			Case 2,6 ; VibratoValue = (SlideStep*SquareWave[VibratoCount])*VibratoDepth
			Case 3,7 ; VibratoValue = (SlideStep*Rnd(-1.0,1.0))*VibratoDepth
		EndSelect
		SetFrequency = True
	    VibratoCount:+VibratoSpeed
	EndMethod

	' ------------------------------------------------------------------------------------------------

	Method DoTremolo()
		If Add=0 Return
        If TremoloCount>64 Then TremoloCount:Mod 64
		Select TremoloWaveForm
			Case 0,4 ; TremoloValue = (VolumeStep*SineWave[TremoloCount])*TremoloDepth
			Case 1,5 ; TremoloValue = (VolumeStep*RampWave[TremoloCount])*TremoloDepth
			Case 2,6 ; TremoloValue = (VolumeStep*SquareWave[TremoloCount])*TremoloDepth
			Case 3,7 ; TremoloValue = (VolumeStep*Rnd(-1.0,1.0))*TremoloDepth
		EndSelect
        TremoloCount:+TremoloSpeed
	EndMethod

EndType
